package cn.liuxiany.alibaba.consumer.config;

import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.common.circuitbreaker.configuration.CircuitBreakerConfigCustomizer;
import io.github.resilience4j.timelimiter.TimeLimiterConfig;
import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JCircuitBreakerFactory;
import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JConfigBuilder;
import org.springframework.cloud.client.circuitbreaker.Customizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;

/**
 * @Description 项目配置
 * @Author liuxiany
 * @Date 2023/11/07
 */
@Configuration
public class WebConfig {

    // 不生效，一直使用的是默认的。
/*    @Bean
    public CircuitBreakerConfigCustomizer testCustomizer() {
        return CircuitBreakerConfigCustomizer
                .of("backendA", builder ->
                        builder.slidingWindowType(CircuitBreakerConfig.SlidingWindowType.COUNT_BASED)
                                .slidingWindowSize(10)
                                .minimumNumberOfCalls(1)
                                .failureRateThreshold(50)
                                .enableAutomaticTransitionFromOpenToHalfOpen()
                                .waitDurationInOpenState(Duration.ofSeconds(10))
                                .permittedNumberOfCallsInHalfOpenState(2)
                                .recordExceptions(java.lang.Throwable.class)
                );
    }*/

    /**
     * 熔断器配置
     * 不知道为什么自定义的熔断规则不生效，一直使用的是默认的。原因：必须引入aop依赖。
     *
     * @return
     */
/*    @Bean
    public Customizer<Resilience4JCircuitBreakerFactory> defaultCustomizer() {
        return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
                .timeLimiterConfig(TimeLimiterConfig.custom().timeoutDuration(Duration.ofSeconds(5)).build())
                .circuitBreakerConfig(circuitBreakerConfig)
                .build());
    }*/

    /**
     * 自定义熔断器规则
     */
    CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
            // 滑动窗口的类型为时间窗口。COUNT_BASED：根据数量计算，slidingWindowSize为次数。TIME_BASED：根据时间计算，slidingWindowSize为秒数
            .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.COUNT_BASED)
            .slidingWindowSize(10) // 时间窗口的大小为60秒
            .minimumNumberOfCalls(1) // 在单位时间窗口内最少需要5次调用才能开始进行统计计算. 计算错误率的最小请求数，不足最小调用次数不会触发任何变化。
            .failureRateThreshold(10f) // 在单位时间窗口内调用失败率达到50%后会启动断路器
//            .slowCallDurationThreshold(Duration.ofSeconds(30)) // 慢调用阀值，请求执行的时间大于该值时会标记为慢调用
//            .slowCallRateThreshold(100) // 慢调用熔断阀值，当慢调用率达到或高于该值时，进入open状态
            .enableAutomaticTransitionFromOpenToHalfOpen() // 允许断路器自动由打开状态转换为半开状态, 默认false，一定时间之后进入half-open。true则通过接口调用。
            .waitDurationInOpenState(Duration.ofSeconds(10)) // 断路器打开状态转换为半开状态需要等待60秒
            .permittedNumberOfCallsInHalfOpenState(2) // 在半开状态下允许进行正常调用的次数，根据此数量的请求计算失败率。低于则close,高于则open。
            .recordExceptions(java.lang.Throwable.class) // 所有异常都当作失败来处理
//            .ignoreExceptions(java.lang.IllegalArgumentException.class) // 不会被计为失败的异常集合，优先级高于recordExceptions
            .build();


}
